;; 对 Emacs 内置功能的扩展

;; Open Emacs config file
(defun my/find-user-init-file ()
  (interactive)
  (find-file-other-window user-init-file))

(defun my/find-user-custom-file ()
  (interactive)
  (if custom-file
      (find-file-other-window custom-file)
    (message "No custom file found.")))

(defun my/recentf-find-file (&optional filter)
  (interactive)
  (let* ((filter (if (functionp filter) filter #'abbreviate-file-name))
         (file (completing-read "Find recent file: "
                                (delete-dups (mapcar filter recentf-list))
                                nil t)))
    (when file
      (find-file file))))

(defun my/new-empty-buffer ()
  (interactive)
  (let ((buf (generate-new-buffer "untitled")))
    (switch-to-buffer buf)
    (funcall 'text-mode)
    buf))

(defun my/smart-beginning-of-line ()
  (interactive "^")
  (let ((oldpos (point)))
    (back-to-indentation)
    (and (= oldpos (point))
         (beginning-of-line))))

(setq cua--rectangle nil)
(defun my/copy-line-or-region ()
  "如果当前有选区则复制选区，否则复制当前行（不包含缩进）"
  (interactive)
  (if (region-active-p)
      (if cua--rectangle
          (cua-copy-region cua--rectangle)
        (kill-ring-save (region-beginning) (region-end)))
    (save-excursion
      (back-to-indentation)
      (kill-ring-save (point) (line-end-position)))))

(defun my/insert-up-newline ()
  (interactive)
  (move-beginning-of-line 1)
  (open-line 1)
  (indent-for-tab-command))

(defun my/insert-down-newline ()
  (interactive)
  (move-end-of-line 1)
  (newline-and-indent))

(defun my/insert-semicolon-newline ()
  ;;(interactive)
  (move-end-of-line 1)
  (insert ";")
  (newline-and-indent))

(defun my/insert-date-and-time ()
  (interactive)
  (insert (format-time-string "%c" (current-time))))

;; 用来增强Ctrl-Backward的功能，默认的行为不够人性化
;; 代码来自https://github.com/manateelazycat/delete-block/blob/master/delete-block.el
;; 代码需要开启 subword-mode
(require 'subword)
(defun my/subword-delete-block-forward ()
  (interactive)
  (if (eobp)
      (message "End of buffer")
    (let* ((syntax-move-point
            (save-excursion
              (skip-syntax-forward (string (char-syntax (char-after))))
              (point)))
           (subword-move-point
            (save-excursion
              (subword-forward)
              (point))))
      (kill-region (point) (min syntax-move-point subword-move-point)))))

(defun my/subword-delete-block-backward ()
  (interactive)
  (if (bobp)
      (message "Beginning of buffer")
    (let* ((syntax-move-point
            (save-excursion
              (skip-syntax-backward (string (char-syntax (char-before))))
              (point)))
           (subword-move-point
            (save-excursion
              (subword-backward)
              (point))))
      (kill-region (point) (max syntax-move-point subword-move-point)))))

;; 摘自crux.el
(defun my/rename-file-and-buffer ()
  "Rename current buffer and if the buffer is visiting a file, rename it too."
  (interactive)
  (let ((filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (rename-buffer (read-from-minibuffer "New name: " (buffer-name)))
      (let* ((new-name (read-file-name "New name: " (file-name-directory filename)))
             (containing-dir (file-name-directory new-name)))
        (make-directory containing-dir t)
        (cond
         ((vc-backend filename) (vc-rename-file filename new-name))
         (t
          (rename-file filename new-name t)
          (set-visited-file-name new-name t t)))))))

;; 摘自crux.el
(defun my/delete-file-and-buffer ()
  "Kill the current buffer and deletes the file it is visiting."
  (interactive)
  (let ((filename (buffer-file-name)))
    (when filename
      (if (vc-backend filename)
          (vc-delete-file filename)
        (when (y-or-n-p (format "Are you sure you want to delete %s? " filename))
          (delete-file filename delete-by-moving-to-trash)
          (message "Deleted file %s" filename)
          (kill-buffer))))))

(provide 'my/extensions)
